package sharemem

/*
#cgo LDFLAGS: -pthread
#include <stdio.h>
#include <sys/shm.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <semaphore.h>
*/
import "C"
import (
	"log"
	"server_cluster/gate/gate_config"

	//	"server_cluster/gate/logger"
	"syscall"
	"unsafe"
)

var Myshm *MyData

type Id_Status struct {
	Id     int32
	Status int8
}

type Id_Num struct {
	Id  int32
	Num int32
}

type Id_Num_Weight struct {
	Id     int32
	Num    int32
	Weight int16
}

type Type_Id struct {
	Type int8
	Id   int32
}

type MyData struct {
	Sem_user [gate_config.SHM_USER_MAX]C.sem_t
	Sem_all  C.sem_t // 全局唯一锁
	// user
	User [gate_config.SHM_USER_MAX]User

	Site_user   int32
	Time_now    int64
	Status      int8 // 主进程状态 0初始化 1运行中 2停止新的连接请求 3 停止新的业务请求
	Status_sync int8
	Stock       int32
}

func Init_myshm() {
	var i int32
	init_mysem(&(Myshm.Sem_all))
	for i = 0; i < gate_config.SHM_USER_MAX; i++ {
		init_mysem(&(Myshm.Sem_user[i]))
	}
	// user
	for i = 0; i < gate_config.SHM_USER_MAX; i++ {
		Myshm.User[i].Meminit(i)
	}
	// system
	Myshm.Site_user = 0
	Myshm.Time_now = 0
	Myshm.Status = 0
	Myshm.Status_sync = 0
	Myshm.Stock = gate_config.SHM_USER_MAX
}

func InitAllUserFd () {
	for i := 0; i < gate_config.SHM_USER_MAX; i++ {
		Myshm.User[i].Fd = -1
	}
}

func init_mysem(sem *C.sem_t) {
	C.sem_init(sem, 1, 1)
}

func Sem_wait(sem *C.sem_t) {
	C.sem_wait(sem)
}

func Sem_post(sem *C.sem_t) {
	C.sem_post(sem)
}

func Get_myshm(myshm **MyData) uintptr {
	pn := C.CString("/")
	key := C.ftok(pn, (C.int)(gate_config.CONF.SHMKEY))
	C.free(unsafe.Pointer(pn))
	var tmp MyData
	shmsize := unsafe.Sizeof(tmp)
	shmid, _, err := syscall.Syscall(syscall.SYS_SHMGET, uintptr(key), shmsize, 01000|0640)
	if err != 0 {
		log.Println("shmget error:", err.Error())
		return 0
	}
	var sharemem uintptr
	sharemem, _, err = syscall.Syscall(syscall.SYS_SHMAT, shmid, 0, 0)
	*myshm = (*MyData)(unsafe.Pointer(sharemem))
	return shmid
}

func Drop_myshm(shmid uintptr) {
	syscall.Syscall(syscall.SYS_SHMCTL, shmid, 0, 0)
}

func GetTimeNow() int64 {
	return Myshm.Time_now
}

func (tmp *Id_Status) IsUse() bool {
	return tmp.Id > 0
}
func (tmp *Id_Status) GetId() int32 {
	return tmp.Id
}
func (tmp *Id_Status) SetId(id int32) {
	tmp.Id = id
}
func (tmp *Id_Status) GetStatus() int8 {
	return tmp.Status
}
func (tmp *Id_Status) SetStatus(status int8) {
	tmp.Status = status
}

func (tmp *Id_Num) IsUse() bool {
	return tmp.Id > 0
}
func (tmp *Id_Num) GetId() int32 {
	return tmp.Id
}
func (tmp *Id_Num) SetId(id int32) {
	tmp.Id = id
}
func (tmp *Id_Num) GetNum() int32 {
	return tmp.Num
}
func (tmp *Id_Num) SetNum(num int32) {
	tmp.Num = num
}

func Create_user_by_id(uid int64, fd int32) *User {
	// 按出入栈规则加解锁 epoll单协程模式免全局锁
	// Sem_wait(&(Myshm.Sem_all))
	if Myshm.Stock == 0 {
		// Sem_post(&(Myshm.Sem_all))
		return nil
	}
	site := Myshm.Site_user
	for i := 0; i < gate_config.SHM_USER_MAX; i++ {
		if site < 0 || site >= gate_config.SHM_USER_MAX {
			site = 0
		}
		if Myshm.User[site].IsUse() {
			site++
			continue
		}
		//须加锁 与清理进程会形成抢占
		Sem_wait(&(Myshm.Sem_user[site]))

		if Myshm.User[site].IsUse() {
			Sem_post(&(Myshm.Sem_user[site]))
			site++
			continue
		}

		Myshm.User[site].use(uid)
		Myshm.User[site].Fd = fd
		Myshm.User[site].AliveTime = Myshm.Time_now
		Myshm.User[site].sessionUpdate()
		// 初始化保存索引
		SetUserMap(uid, &(Myshm.User[site]))
		// 游标滑动
		Myshm.Site_user++
		if Myshm.Site_user < 0 || Myshm.Site_user >= gate_config.SHM_USER_MAX {
			Myshm.Site_user = 0
		}
		Myshm.Stock--
		Sem_post(&(Myshm.Sem_user[site]))
		// Sem_post(&(Myshm.Sem_all))
		return &(Myshm.User[site])
		//
	}
	// Sem_post(&(Myshm.Sem_all))
	// 服务器爆满
	return nil

}

func (u *User) Get_user_by_index(uid int64, fd int32) bool {
	// 锁前预判断 提升效率 返错安全 通过不安全
	if !u.isMe(uid) {
		return false
	}
	Sem_wait(&(Myshm.Sem_user[u.Index]))
	// 锁后再判断 保证安全
	if !u.isMe(uid) {
		Sem_post(&(Myshm.Sem_user[u.Index]))
		return false
	}
	u.Fd = fd
	u.sessionUpdate()
	Sem_post(&(Myshm.Sem_user[u.Index]))
	return true
}

func (u *User) Clean_user() {
	index := u.Index
	// Sem_wait(&(Myshm.Sem_user[index]))
	// 清余索引
	DeleteUserMap(u.getId())
	// 清理内存
	u.Meminit(index)
	Myshm.Stock++
	// Sem_post(&(Myshm.Sem_user[index]))
}
